package entity;

import java.io.Serializable;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.LinkedList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;

/**
 * Classe che modella l'utente registrato a Shipping Share
 * @author ale
 */

@Entity
public class UtenteRegistrato implements Serializable {
    
    /**
     * Ruolo dell'utente all'interno del sistema, stabilisce i privilegi che ha l'utente
     */
    public enum Ruolo {

        /**
         * Utente semplice
         */
        UTENTE,
        /**
         * Moderatore: ha tutti i privilegi di utente semplice, più quelli di moderazione
         */
        MODERATORE,
        /**
         * Amministratore: unico nel sistema, ha tutti i privilegi del moderatore, più quelli di amministrazione
         */
        AMMINISTRATORE,
        /**
         * Utente registrato ma che non ha ancora verificato la propria e-mail, non ha alcun privilegio in più del guest
         */
        NONVERIFICATO
    }
    
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    /**
     * Nome dell'utente
     */
    protected String nome;
    /**
     * Cognome dell'utente
     */
    protected String cognome;
    /**
     * Recapito telefonico dell'utente
     */
    protected String telefono;
    /**
     * Indirizzo e-mail dell'utente
     */
    @OneToOne(cascade= CascadeType.PERSIST)
    protected IndirizzoEmail indirizzoEmail;
    /**
     * Indirizzo di residenza dell'utente
     */
    @ManyToOne(cascade= CascadeType.PERSIST)
    protected IndirizzoAbitazione indirizzo;
    /**
     * True sse l'utente è stato bannto dal sistema
     */
    protected boolean bannato;
    /**
     * Lista di modalità di pagamento accettate dall'utente, obbligatorio che contenga una modalità PayPal
     */
    @OneToMany(cascade= CascadeType.PERSIST)
    protected List<ModalitaPagamento> modalitaPagamento;
    /**
     * Lista di annunci creati dall'utente
     */
    @OneToMany(mappedBy = "creatoreAnnuncio", cascade= CascadeType.PERSIST)
    protected List<Annuncio> annunciCreati;
    /**
     * Lista di adesioni, associazioni tra l'utente e l'annuncio a cui è iscritto
     */
    @OneToMany(mappedBy = "iscritto", cascade= CascadeType.PERSIST)
    protected List<Adesione> adesioni;
    /**
     * Password crittografata (MD5) dell'utente
     */
    protected String crittoPassword;
    /**
     * Informazioni sui feedback ricevuti dall'utente
     */
    @OneToOne(cascade= CascadeType.PERSIST)
    protected Feedback feedback;
    /**
     * Id di facbeook dell'utente, solo per utenti che si sono collegati a Facebook
     */
    protected String facebookId;
    /**
     * Ruolo dell'utente (non verificato, utente semplice, moderatore, amministratore)
     */
    protected Ruolo ruolo;
    /**
     * Id univoco assegnato in fase di registrazione per la verifica e-mail/ cambio password
     */
    protected String uuid;
    
    /**
     * Recupera le informazioni sulla modalità di pagamento PayPal, se esistono
     * @return le informazioni sulla modalità di pagamento PayPal, se esistono
     */
    public PayPal getPaypal(){
        for (ModalitaPagamento m: modalitaPagamento){
            if (m instanceof PayPal)
                return (PayPal) m;
        }
        
        return null;
    }
    
    /**
     * Verifica se l'utente si è mai collegato a Facebook
     * @return true sse l'utente si è già collegato a Facebook (cioè ha un facebook id non null)
     */
    public boolean isCollegatoFb(){
        return !(facebookId == null || facebookId.equals("null"));
    }
    
    /**
     * Verifica se l'utente è già stato verificato
     * @return
     */
    public boolean isVerificato(){
        return !ruolo.equals(Ruolo.NONVERIFICATO);
    }

    /**
     * Recupera l'uuid attuale dell'utente
     * @return l'uuid attuale dell'utente
     */
    public String getUuid() {
        return uuid;
    }

    /**
     * Imposta un nuovo uuid all'utente
     * @param uuid nuovo uuid casuale per l'utente
     */
    public void setUuid(String uuid) {
        this.uuid = uuid;
    }
    
    /**
     * Recupera la lista di annunci ai quali l'utente è iscritto (infatti solo le adesioni sono memorizzate)
     * @return la lista di annunci ai quali l'utente è iscritto
     */
    public List<Annuncio> getAnnunciIscritto(){
        List<Annuncio> res = new LinkedList<Annuncio>();
        for (Adesione a: adesioni){
            res.add(a.getAnnuncio());
        }
        return res;
    }
    
    /**
     * Get the value of ruolo
     *
     * @return the value of ruolo
     */
    public Ruolo getRuolo() {
        return ruolo;
    }

    /**
     * Set the value of ruolo
     *
     * @param ruolo new value of ruolo
     */
    public void setRuolo(Ruolo ruolo) {
        this.ruolo = ruolo;
    }

    /**
     * Verifica se l'utente ha i privilegi di moderatore (quindi, se è moderatore o amministratore)
     * @return true sse l'utente ha i privilegi di moderatore
     */
    public boolean isModeratore(){
        return ruolo.equals(Ruolo.MODERATORE) || ruolo.equals(Ruolo.AMMINISTRATORE);
    }
    
    /**
     * Verifica se l'utente ha i privilegi di amministratore
     * @return true sse l'utente è amministratore
     */
    public boolean isAmministratore(){
        return ruolo.equals(Ruolo.AMMINISTRATORE);
    }
    
    /**
     * Get the value of facebookId
     *
     * @return the value of facebookId
     */
    public String getFacebookId() {
        return facebookId;
    }

    /**
     * Set the value of facebookId
     *
     * @param facebookId new value of facebookId
     */
    public void setFacebookId(String facebookId) {
        this.facebookId = facebookId;
    }

    /**
     * Get the value of feedback
     *
     * @return the value of feedback
     */
    public Feedback getFeedback() {
        return feedback;
    }

    /**
     * Set the value of feedback
     *
     * @param feedback new value of feedback
     */
    public void setFeedback(Feedback feedback) {
        this.feedback = feedback;
    }

    /**
     * Get the value of crittoPassword
     *
     * @return the value of crittoPassword
     */
    public String getCrittoPassword() {
        return crittoPassword;
    }

    /**
     * Set the value of crittoPassword
     *
     * @param password 
     */
    public void setCrittoPassword(String password) {
        this.crittoPassword = cripta(password);
    }

    /**
     * Unico punto in cui si esegue la crittografia della password
     * In questo modo non ci si confonde con gli algoritmi, tutte le volte che serve si richiama questo
     *
     * @param password password NON crittografata
     * @return password crittografata
     */
    public static String cripta(String password) {
        if (password == null) return null;
        byte[] defaultBytes = password.getBytes();
        try {
            MessageDigest algorithm = MessageDigest.getInstance("MD5");
            algorithm.reset();
            algorithm.update(defaultBytes);
            byte messageDigest[] = algorithm.digest();
            
            StringBuilder hexString = new StringBuilder();
            for (int i = 0; i < messageDigest.length; i++) {
                hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
            }
            String res = hexString.toString();
            System.out.println("sto criptando '" + password + "', md5 =" + res);
            return res;
        } catch (NoSuchAlgorithmException nsae) {
            return "";
        }
    }

    /**
     * Get the value of adesioni
     *
     * @return the value of adesioni
     */
    public List<Adesione> getAdesioni() {
        return adesioni;
    }

    /**
     * Set the value of adesioni
     *
     * @param adesioni new value of adesioni
     */
    public void setAdesioni(List<Adesione> adesioni) {
        this.adesioni = adesioni;
    }


    /**
     * Get the value of annunciCreati
     *
     * @return the value of annunciCreati
     */
    public List<Annuncio> getAnnunciCreati() {
        return annunciCreati;
    }

    /**
     * Set the value of annunciCreati
     *
     * @param annunciCreati new value of annunciCreati
     */
    public void setAnnunciCreati(List<Annuncio> annunciCreati) {
        this.annunciCreati = annunciCreati;
    }

    /**
     * Get the value of modalitaPagamento
     *
     * @return the value of modalitaPagamento
     */
    public List<ModalitaPagamento> getModalitaPagamento() {
        return modalitaPagamento;
    }

    /**
     * Set the value of modalitaPagamento
     *
     * @param modalitaPagamento new value of modalitaPagamento
     */
    public void setModalitaPagamento(List<ModalitaPagamento> modalitaPagamento) {
        this.modalitaPagamento = modalitaPagamento;
    }

    /**
     * Get the value of bannato
     *
     * @return the value of bannato
     */
    public boolean isBannato() {
        return bannato;
    }

    /**
     * Set the value of bannato
     *
     * @param bannato new value of bannato
     */
    public void setBannato(boolean bannato) {
        this.bannato = bannato;
    }

    /**
     * Get the value of indirizzo
     *
     * @return the value of indirizzo
     */
    public IndirizzoAbitazione getIndirizzo() {
        return indirizzo;
    }

    /**
     * Set the value of indirizzo
     *
     * @param indirizzo new value of indirizzo
     */
    public void setIndirizzo(IndirizzoAbitazione indirizzo) {
        this.indirizzo = indirizzo;
    }

    /**
     * Get the value of email
     *
     * @return the value of email
     */
    public IndirizzoEmail getEmail() {
        return indirizzoEmail;
    }

    /**
     * Set the value of email
     *
     * @param email new value of email
     */
    public void setEmail(IndirizzoEmail email) {
        this.indirizzoEmail = email;
    }

    /**
     * Get the value of telefono
     *
     * @return the value of telefono
     */
    public String getTelefono() {
        return telefono;
    }

    /**
     * Set the value of telefono
     *
     * @param telefono new value of telefono
     */
    public void setTelefono(String telefono) {
        this.telefono = telefono;
    }

    /**
     * Get the value of cognome
     *
     * @return the value of cognome
     */
    public String getCognome() {
        return cognome;
    }

    /**
     * Set the value of cognome
     *
     * @param cognome new value of cognome
     */
    public void setCognome(String cognome) {
        this.cognome = cognome;
    }

    /**
     * Get the value of nome
     *
     * @return the value of nome
     */
    public String getNome() {
        return nome;
    }

    /**
     * Set the value of nome
     *
     * @param nome new value of nome
     */
    public void setNome(String nome) {
        this.nome = nome;
    }

    /**
     * Recupera l'id dell'utente
     * @return l'id dell'utente
     */
    public Long getId() {
        return id;
    }

    /**
     * Imposta l'id dell'utente
     * @param id l'id dell'utente
     */
    public void setId(Long id) {
        this.id = id;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        if (!(object instanceof UtenteRegistrato)) {
            return false;
        }
        UtenteRegistrato other = (UtenteRegistrato) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "entity.UtenteRegistrato[ id=" + id + " ]";
    }
    
}
